<?php

	App::import('Component', 'RequestHandler');

	class UploadedFileXhr
	{
		var $file;
		
		function save($path)
		{
			$input = fopen('php://input', 'r');
			$temp = tmpfile();
			$size = stream_copy_to_stream($input, $temp);
			fclose($input);
			
			if ($size != $this->getSize()) {
				return false;
			}
		
			$target = fopen($path, "w");
			fseek($temp, 0, SEEK_SET);
			stream_copy_to_stream($temp, $target);
			fclose($target);
		
			return true;
		}
		
		function getName() { return $this->file; }
		
		function getSize()
		{
			if (isset($_SERVER['CONTENT_LENGTH'])) {
				return (int) $_SERVER['CONTENT_LENGTH'];
			}
			else {
				throw new Exception('Getting content length is not supported.');
			}
		}
	}
	
	class UploadedFileForm
	{
		var $file;
		
		function save($path)
		{
			if (!move_uploaded_file($this->file['tmp_name'], $path)) {
				return false;
			}
			return true;
		}
		
		function getName() { return $this->file['name']; }
		
		function getSize() { return $this->file['size']; }
	}

	class UploadFileComponent extends Object
	{
		private $uploaded;
		private $settings = array();
		
		private $controller = true;
		/*
		function startup(&$controller)
		{
			$this->controller =& $controller;
		}
		*/
		private function checkServerSettings()
		{
			$postSize = $this->toBytes(ini_get('post_max_size'));
			$uploadSize = $this->toBytes(ini_get('upload_max_filesize'));
		
			if ($postSize < $this->settings['sizeLimit'] || $uploadSize < $this->settings['sizeLimit']) {
				$size = max(1, $this->settings['sizeLimit'] / 1024 / 1024) . 'M';
				die("{'error':'increase post_max_size and upload_max_filesize to {$size}'}");
			}
		}
		
		private function toBytes($str)
		{
			$val = trim($str);
			$last = strtolower($str[strlen($str) - 1]);
			switch ($last) {
				case 'g':
					$val *= 1024;
				case 'm':
					$val *= 1024;
				case 'k':
					$val *= 1024;
			}
			return $val;
		}
		
		public function handle($file, $settings = array())
		{
			$this->settings = array_merge(
				array(
					'allowedExtensions' => array(),
					'sizeLimit' => 10485760,
					'replaceOldFile' => false,
					'path' => null,
					'createPath' => false,
					'fileName' => null
				),
				$settings
			);
		
			$this->settings['allowedExtensions'] = array_map('strtolower', $this->settings['allowedExtensions']);
			
			$this->checkServerSettings();
			
			$request_handler = new RequestHandlerComponent;
			
			if ($request_handler->isAjax()) {
				$this->uploaded = new UploadedFileXhr;
				$this->uploaded->file = $file;
			}
			else if (is_array($file)) {
				$this->uploaded = new UploadedFileForm;
				$this->uploaded->file = $file;
			}
			else {
				$this->uploaded = false;
			}
			
			if (!is_dir($this->settings['path']) && !file_exists($this->settings['path'])) {
				if ($this->settings['createPath']) {
					if (!mkdir($this->settings['path'], 0777, true)) {
						return array('error' => __('No existe y no se logró crear la ruta epecificada. Por favor vuelva a intentar más tarde.', true));
					}
				}
				else {
					return array('error' => __('No existe la ruta epecificada. Por favor vuelva a intentar más tarde.', true));
				}
			}
			
			if (!is_writable($this->settings['path'])) {
				return array('error' => __('Error del Servidor. No se puede escribir en el directorio especificado.', true));
			}
		
			if (!$this->uploaded) {
				return array('error' => __('Se debe seleccionar un archivo para subir.', true));
			}
		
			$size = $this->uploaded->getSize();
		
			if ($size == 0) {
				return array('error' => __('El archivo viene vacío.', true));
			}
		
			if ($size > $this->settings['sizeLimit']) {
				return array('error' => __('El archivo es demasiado grande.', true));
			}
		
			$pathinfo = pathinfo($this->uploaded->getName());
			
			$filename = ($this->settings['fileName'] ? $this->settings['fileName'] : $pathinfo['filename']);
			$extension = $pathinfo['extension'];
		
			if ($this->settings['allowedExtensions'] && !in_array(strtolower($extension), $this->settings['allowedExtensions'])) {
				$these = implode(', ', $this->settings['allowedExtensions']);
				return array('error' => sprintf(__('El archivo no es valido, debe ser %s.', true), $these));
			}
			
			if (!$this->settings['replaceOldFile']) {
				while (file_exists($this->settings['path'] . DS . $filename . '.' . $extension)) {
					$filename .= rand(10, 99);
				}
			}
			
			if ($this->uploaded->save($this->settings['path'] . DS . $filename . '.' . $extension)) {
				return array(
					'success' => true,
					'file' => $filename . '.' . $extension,
				);
			}
			else {
				return array('error' => 'Could not save uploaded file.'.'The upload was cancelled, or server error encountered');
			}
		}
	}
